local SendRPCToServer = GLOBAL.SendRPCToServer
local RPC = GLOBAL.RPC
local ACTIONS = GLOBAL.ACTIONS
local TUNING = GLOBAL.TUNING

local last_boss_atk = 0
local last_rpc_time = 0
local last_player_hit = 0
local last_boss_fire = 0
local BossAtkCD = TUNING.DRAGONFLY_ATTACK_PERIOD
local BossSleepCD = 1.2
local anim_reset_time = BossAtkCD / 3 * 2
local rpc_cd = 0.05
local KEY = false
local boss_name = "dragonfly"
local PlayerSpeed = 6
local IsLeave = false

local shouldplay = false
local allowplay = false
local rem_pos = nil
local sleepstate = false

local BossAtkRange = TUNING.DRAGONFLY_ATTACK_RANGE + 2      -- 实际跑路距离增加容错
local upFrames = 11                                         -- 上行帧率应该在6-16之间
local temp_dis = 99999999
local keepauto = false
local last_boss_vomit = 0
local last_boss_sleep_pst = 0
local memory_pos

local function retsetState()
    shouldplay,allowplay,keepauto,sleepstate = false, false, false,false
    rem_pos = nil
    temp_dis = 99999999
end

local function playerStop()
    SendRPCToServer(RPC.StopWalking)
    SendRPCToServer(RPC.StopControl, ACTIONS.ABANDON_QUEST.code)
end

local function playerWalk()
    SendRPCToServer(RPC.ClearActionHold)
    SendRPCToServer(RPC.LeftClick, ACTIONS.WALKTO.code, memory_pos.x, memory_pos.z, nil, nil, nil, nil, nil, nil, false)
    SendRPCToServer(RPC.ClearActionHold)
    SendRPCToServer(RPC.StopControl, 0)
end

AddPrefabPostInit(boss_name, function(inst)
    local player = GLOBAL.ThePlayer
    local isSleep
    inst:DoPeriodicTask(GLOBAL.FRAMES, function()
        if KEY then
            local now_time = GLOBAL.GetTime()
            if inst and inst.AnimState then
                if c_anim("atk", inst) then
                    if now_time - last_boss_atk >= anim_reset_time then
                        last_boss_atk = now_time + upFrames * GLOBAL.FRAMES
                    end
                elseif c_anim("fire_on", inst) then
                    if now_time - last_boss_fire >= anim_reset_time then
                        last_boss_fire = now_time
                        shouldplay = true
                        allowplay = true
                    end
                elseif c_anim("sleep_loop", inst) then
                    sleepstate = true
                elseif c_anim("sleep_pst", inst) then
                    if now_time - last_boss_sleep_pst >= anim_reset_time then
                        last_boss_sleep_pst = now_time
                    end
                elseif c_anim("death", inst) then
                    KEY = false
                    playerStop()
                    TIP("走位龙蝇", "green", "龙蝇已被自动击杀！感谢您的使用。", "chat")
                end
                isSleep = c_anim({"sleep_loop", "hit_large", "hit_ground"}, inst)
            end
            if player then
                local boss_pos = inst:GetPosition()
                local player_pos = player:GetPosition()
                if not shouldplay then
                    local mobiletime = (BossAtkRange-math.sqrt(boss_pos:DistSq(player_pos))) / PlayerSpeed
                    local shouldleave = (now_time > last_boss_atk + BossAtkCD - mobiletime  -- 开始时间
                    and now_time < last_boss_atk + BossAtkCD)                               -- 结束时间
                    or now_time < last_boss_atk                                             -- 攻击时间完成前求处于逃避状态
                    or (now_time > last_boss_sleep_pst + BossSleepCD - mobiletime           -- 睡醒后就跑
                    and now_time < last_boss_sleep_pst + BossSleepCD)

                    if now_time - last_rpc_time >= rpc_cd and keepauto then
                        -- 走位走位
                        if shouldleave and GetAggro(inst) == player and not isSleep then
                            last_rpc_time = now_time
                            SendRPCToServer(RPC.StopControl, ACTIONS.ABANDON_QUEST.code)
                            local dirx, diry = GetDirectionAToB(boss_pos, player_pos, "down")
                            SendRPCToServer(RPC.DirectWalking, dirx, diry)
                            IsLeave = true
                        -- 打打打
                        else
                            if IsLeave then                                                                                   -- 从离开到攻击
                                rem_pos = player_pos
                                temp_dis = boss_pos:DistSq(rem_pos)
                                -- print(math.sqrt(temp_dis))
                            end
                            IsLeave = false
                            last_rpc_time = now_time
                            SendRPCToServer(RPC.StopWalking)
                            SendRPCToServer(RPC.AttackButton, inst, false, true)
                        end
                        if rem_pos then
                            local dis = boss_pos:DistSq(rem_pos)
                            if dis > temp_dis + 4 then
                                retsetState()
                                SendRPCToServer(RPC.DirectWalking, 0.1, 0.1)
                                player:DoTaskInTime(0.1, playerStop)
                                last_boss_vomit = now_time
                                if memory_pos then
                                    player:DoTaskInTime(0.5, playerWalk)
                                    TIP("走位龙蝇", "pink", "回归位置", "chat")
                                else
                                    TIP("走位龙蝇", "blue", "龙蝇去吐虫子了, 你也调整下站位吧", "chat")
                                end
                            end
                        end
                    end
                else
                    if allowplay then
                        allowplay = false
                        local pan = GetItemFromAll("panflute")
                        if pan then
                            SendRPCToServer(RPC.StopControl, ACTIONS.ABANDON_QUEST.code)
                            SendRPCToServer(RPC.StopWalking)
                            -- 演奏排箫
                            SendRPCToServer(RPC.UseItemFromInvTile, ACTIONS.PLAY.code, pan)
                        else
                            playerStop()
                            local dirx, diry = GetDirectionAToB(boss_pos, player_pos, "down")
                            SendRPCToServer(RPC.DirectWalking, dirx, diry)
                            TIP("走位结束","red","没排箫，溜了溜了", "chat")
                            KEY = false
                        end
                    else
                        if sleepstate or now_time - last_boss_fire > 9 then               -- 需要多长时间演奏排箫
                            SendRPCToServer(RPC.ClearActionHold)
                            shouldplay = false
                            sleepstate = false
                        end
                    end
                end
                if math.sqrt(boss_pos:DistSq(player_pos)) <= 1.5 * BossAtkRange and not keepauto 
                and now_time > last_boss_vomit + 10                                      -- 吐虫子至少10秒吧 
                then
                    keepauto = true
                    TIP("走位龙蝇", "green", "已接管操作", "chat")
                end
            end
        end
    end)
end)

local function fn()
    KEY = not KEY
    if KEY then
        if GLOBAL.TheInput:IsKeyDown(GLOBAL.KEY_LALT) then 
            TIP("回归模式", "pink", "已开启, 请装备好武器和头盔", "chat")
            memory_pos = GLOBAL.ThePlayer:GetPosition()
        else
            TIP("走位龙蝇", "green", "已开启, 请装备好武器和头盔", "chat")
            memory_pos = nil
        end
    else
        TIP("走位龙蝇", "red", "关闭", "chat")
        return
    end
    GLOBAL.ThePlayer:EnableMovementPrediction(true)
    if GLOBAL.ThePlayer.components.locomotor then
        PlayerSpeed = GLOBAL.ThePlayer.components.locomotor:GetSpeedMultiplier()*GLOBAL.ThePlayer.components.locomotor:GetRunSpeed()
        if PlayerSpeed ~= 6 then
            TIP("走位龙蝇", "red", "当前移速不稳定, 误差较大", "chat")
        end
    end
    GLOBAL.ThePlayer:EnableMovementPrediction(false)
    local pingN = GLOBAL.TheNet:GetAveragePing()
    if pingN >= 60 then
        TIP("走位龙蝇", "red", "当前延迟较大("..tostring(pingN).."ms), 走位可能频繁失败", "chat")
    end
    retsetState()
end

if GetModConfigData("sw_autodragon") == "biubiu" then
    DEAR_BTNS:AddDearBtn(GLOBAL.GetInventoryItemAtlas("critter_dragonling_builder.tex"), "critter_dragonling_builder.tex", "自动打龙蝇", "该功能需要开启洞穴的世界", true, fn)
else
    AddBindBtn("sw_autodragon", fn)
end

